<?php

class Url {

    private $scheme;
    public function getScheme() { return $this->scheme; }

    private $site;
    public function getSite() { return $this->site; }

    private $path;
    public function getPath() { return $this->path; }

    /**
     * @return array
     */
    public function getPathChunksArray() {
        return array_filter( explode('/', $this->path) );
    }

    private $ancor;
    public function getAncor() { return $this->ancor; }

    private $hParams;
    public function getParamsAsHash() { return $this->hParams; }

    /**
     * @return Url
     */
    public function removeParam($name) {

        if (isset($this->hParams[$name]))
            unset($this->hParams[$name]);

        return $this;
    }

    /**
     * @return Url
     */
    public function addParam($name, $value) {
        $this->hParams[$name] = $value;
        return $this;
    }

    public function setParams(array $hParams) {
        $this->hParams = $hParams;
        return $this;
    }

    public function getParamsAsText() { return self::composeParams($this->hParams); }

    private static function composeParams(array $hParams = array()) {

        if (!$hParams) return '';

        $result = '?';

        foreach ($hParams as $key => $val) {
            $result .= $key . '=' . $val . '&';
        }

        return rtrim($result, '&');
    }

    private function __construct($url) {

        if (!preg_match('~^(.+)://([^/?]*)([^?]*)((?:\?[^#]*)?)((?:#.*)?)$~', $url, $arrMatches))
            throw new Exception("Incorrect url '$url'");

        list($null, $this->scheme, $this->site, $this->path, $params, $this->ancor) = $arrMatches;

        $this->hParams = array();

        if ($params) {

            $params = trim($params, '?&');

             foreach (explode('&', $params) as $pair) {
                if (count($arr = explode('=', $pair)) == 2) {
                    $this->hParams[$arr[0]] = $arr[1];
                }
             }
        }
    }

    /**
     * @return Url
     */
    public static function create($url) { return new self($url); }

    /**
     * @return Url
     */
    public static function createOnSite($url) { return self::create('http://' . $_SERVER['HTTP_HOST'] . $url); }

    private static $oCurrentUrl;

    /**
     * @return Url
     */
    public static function createCurrent() {

        if (!self::$oCurrentUrl)
            self::$oCurrentUrl = self::createOnSite($_SERVER['REQUEST_URI']);

        return self::$oCurrentUrl;
    }

    public static function setCurrent(Url $oUrl) {
        self::$oCurrentUrl = null;
        $_SERVER['REQUEST_URI'] = $oUrl->composeLinkOnSite();
        $_GET = self::createCurrent()->getParamsAsHash();
    }

    public function composeLinkOnSite() {
        $url = $this->getPath() . $this->getParamsAsText() . $this->getAncor();
        return trim($url, '#&');
    }

    public function composeAbsoluteLink() {
        return $this->getScheme() . '://' . $this->getSite() . $this->composeLinkOnSite();
    }

//    TODO
//    public function getRelativeLink() {
//    }

    public static function composeUrl($path, array $hParams = array(), $ancor = '') {
        return $path . self::composeParams($hParams) . ($ancor ? '#' . $ancor : '');
    }

    public static function trimAncor($path) {
        if (($sharpPos = strpos($path,'#')) !== false) {
            $path = substr($path, 0, $sharpPos);
        }
        return $path;
    }

    public static function isCurrent($path) {
        return $path == Url::trimAncor( Url::createCurrent()->composeLinkOnSite() );
    }

    public static function isSubpage($path) {
        return $path == Url::createCurrent()->getPath();
    }

    public static function rewrite($fromRegex, $toRegex) {

        self::createCurrentNotRewrited();

//        preg_match($fromRegex, $_SERVER['REQUEST_URI'], $m);
//        Debug::show('',$m);

        $_SERVER['REQUEST_URI'] = preg_replace($fromRegex, $toRegex, $_SERVER['REQUEST_URI'], 1, $replaceNumbers);

        if ($replaceNumbers) {
            self::$oCurrentUrl = null;
            $_GET = self::createCurrent()->getParamsAsHash();
        }
    }

    private static $oCurrentNotRewritedUrl;

    /**
     * @return Url
     */
    public static function createCurrentNotRewrited() {

        if (!self::$oCurrentNotRewritedUrl)
            self::$oCurrentNotRewritedUrl = self::createCurrent();

        return self::$oCurrentNotRewritedUrl;
    }

    public static function fixEndSlash() {

        $chunks = explode('?', $_SERVER['REQUEST_URI']);
        if (strpos($chunks[0], '.') !== false) return;

        $chunks[0] = Dir::addEndslash($chunks[0]);
        $correctUrl = implode('?', $chunks);

        if ($correctUrl != $_SERVER['REQUEST_URI']) {
            Output::redirect($correctUrl);
            //Debug::show('$correctUrl', $correctUrl);
        }
    }
}

?>